#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

using System.Reflection;
using System.Text;
using KLib.Physics.Collisions;
#endregion

namespace KLib.Physics
{
    /// <summary>
    /// A Body with Geometry.
    /// </summary>
    public class RigidBody : Body
    {
        #region Fields
        private List<Geom> geoms;
        private AABB bounds;

        private float frictionCoefficient;
        #endregion

        #region Properties
        public List<Geom> Geometry
        {
            get { return geoms; }
            set
            {
                this.geoms = value;
            }
        }

        public float FrictionCoefficient
        {
            get { return frictionCoefficient; }
            set { frictionCoefficient = value; }
        }

        public AABB Bounds
        {
            //Quick hack, fix
            get { return geoms[0].Bounds; }
        }
        #endregion

        #region Initialization

        public RigidBody()
        {
            this.geoms = new List<Geom>();
            this.bounds = new AABB();
        }

        public RigidBody(Geom geom)
        {
            this.geoms = new List<Geom>();
            //Quick hack, fix
            //this.bounds = geoms[0].Bounds;
            this.bounds = new AABB();
        }

        public RigidBody(RigidBody body)
        {
            this.geoms = new List<Geom>(body.Geometry.Count);
            foreach (Geom geometry in body.Geometry)
            {
                Geom newGeom = new Geom(this,geometry.LocalVertices);
                newGeom.RestitutionCoefficient = geometry.RestitutionCoefficient;
                this.geoms.Add(newGeom);
            }
            //Quick hack, fix
            this.bounds = geoms[0].Bounds;
            this.FrictionCoefficient = body.frictionCoefficient;
            this.Enabled = body.enabled;
            this.IgnoresGravity = body.ignoresGravity;
            this.IsStatic = body.IsStatic;
            this.Mass = body.Mass;
            this.MomentOfInertia = body.MomentOfInertia;
            this.Position = body.Position;
            this.Rotation = body.Rotation;
        }
        #endregion

        #region Methods
        
        #region Move() | MoveTo()
        public override void Move(Vector2 amount)
        {
            base.Move(amount);
            for (int i = 0; i < geoms.Count; i++)
            {
                //geoms[i].Move(amount);
            }
        }

        public override void MoveTo(Vector2 position)
        {
            Vector2 changeInPosition = Vector2.Subtract(position,this.position);
            for (int i = 0; i < geoms.Count; i++)
            {
                //geoms[i].Move(changeInPosition);
            }
            base.MoveTo(position);
        }
        #endregion

        #region Rotate() | RotateTo()
        public override void Rotate(float radians)
        {
            base.Rotate(radians);
            for (int i = 0; i < geoms.Count; i++)
            {
                //geoms[i].Rotate(radians);
            }
        }

        public override void RotateTo(float radians)
        {
            float changeInRotation = radians - this.rotation;
            base.RotateTo(radians);
            /*for (int i = 0; i < geoms.Count; i++)
            {
                geoms[i].Rotate(changeInRotation);
            }*/
        }
        #endregion

        #region Update()
        public override void Update()
        {
            bounds = geoms[0].Bounds;
            for (int i = 0; i < geoms.Count; i++)
            {
                //geoms[i].MoveTo(this.Position);
                //geoms[i].RotateTo(this.rotation);
                geoms[i].Update();
                //Quick hack, fix

                if (geoms[i].Bounds.Min.X < bounds.Min.X)
                    bounds.Min.X = geoms[i].Bounds.Min.X;
                if (geoms[i].Bounds.Min.Y < bounds.Min.Y)
                    bounds.Min.Y = geoms[i].Bounds.Min.Y;

                if (geoms[i].Bounds.Max.X > bounds.Max.X)
                    bounds.Max.X = geoms[i].Bounds.Max.X;
                if (geoms[i].Bounds.Max.Y > bounds.Max.Y)
                    bounds.Max.Y = geoms[i].Bounds.Max.Y;
            }
        }
        #endregion
        #endregion

        #region Static Methods
        #endregion

        #region Helper Methods

        #endregion

        #region Saving
        public string SaveString(string parentPropertyName)
        {
            /*StringBuilder str = new StringBuilder();
            PropertyInfo[] properties = this.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy);

            foreach (PropertyInfo property in properties)
            {
                object[] attr = property.GetCustomAttributes(typeof(Microsoft.Xna.Framework.Content.ContentSerializerIgnoreAttribute), false);
                if (attr.Length > 0
                    || !property.CanWrite) continue;

                if (property.PropertyType == typeof(string)
                    || property.PropertyType == typeof(int)
                    || property.PropertyType == typeof(float)
                    || property.PropertyType == typeof(bool))
                    str.AppendLine(parentPropertyName + ":" + property.Name + ":" + property.GetValue(this, null).ToString());
                else if (property.PropertyType == typeof(Geom))
                {
                    str.Append(Utilities.ContentExporter.GetExportContentString<Geom>(this.Geometry, parentPropertyName + ":" + property.Name));
                }
            }
            return str.ToString();*/
            return string.Empty;
        }
        #endregion
    }
}
